package org.sch.util;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.StringUtils;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;

/**
 * @program: javatest
 * @description: 重写springIOC练习1
 * @author: sch
 * @create: 2020-07-06 22:59
 **/
public class SchIocContentUtilsPractise1 {
    private String configFileName;

    Map<String, Object> iocMap = new HashMap<>();

    public SchIocContentUtilsPractise1(String configFileName) {
        this.configFileName = configFileName;
        try {
            parseXml(configFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void parseXml(String fileName) throws Exception {
        //1,读取文件
        String configPath = this.getClass().getResource("/").getPath();
        File file = new File(configPath + configFileName);

        //2,解析xml
        SAXReader saxReader = new SAXReader();
        Document rootDocument = saxReader.read(file);

        boolean autowiedFlag = false;
        //2.1遍历根节点
        Element rootElement = rootDocument.getRootElement();
        String autowireType = rootElement.attribute("default-autowire").getValue();
        if (!StringUtils.isEmpty(autowireType)) {
            autowiedFlag = true;
        }
        for (Iterator<Element> firstChiledIterator = rootElement.elementIterator(); firstChiledIterator.hasNext(); ) {
            Element firstChiledElement = firstChiledIterator.next();

            //2.2获取id,class属性
            String beanId = firstChiledElement.attribute("id").getValue();
            String beanClassStr = firstChiledElement.attribute("class").getValue();

            //2.3遍历二级节点，进行对象注入
            Class<?> beanClass = Class.forName(beanClassStr);
            Object obj = null;
            for (Iterator<Element> secondChiledIterator = firstChiledElement.elementIterator(); secondChiledIterator.hasNext(); ) {
                Element secondChiledElement = secondChiledIterator.next();
                //判断是setter注入还是构造函数注入
                String name = secondChiledElement.getName();
                String secondRefName = secondChiledElement.attribute("ref").getValue();
                Object injectObj = iocMap.get(secondRefName);
                if ("property".equals(name)) {
                    obj = beanClass.newInstance();
                    //setter方法注入
                    String secondPropertyName = secondChiledElement.attribute("name").getValue();

                    Field field = beanClass.getDeclaredField(secondPropertyName);
                    field.setAccessible(true);
                    field.set(obj, injectObj);

                } else {
                    //构造函数注入
                    Constructor constructor = beanClass.getConstructor(injectObj.getClass().getInterfaces()[0]);
                    obj = constructor.newInstance(injectObj);
                }
            }

            //2.4自动装配
            if (null == obj && autowiedFlag) {
                Field[] fields = beanClass.getDeclaredFields();
                obj = beanClass.newInstance();
                //判断byType或byName
                if ("byName".equals(autowireType)) {
                    //根据名称：拿到field 使用setter注入
                    for (Field field : fields) {
                        field.setAccessible(true);
                        //属性类型、属性名称
                        Class<?> fieldClass = field.getType();
                        Object injectObj = iocMap.get(field.getName());

                        if (Objects.nonNull(injectObj) && injectObj.getClass().getInterfaces()[0].getName().equals(fieldClass.getName())) {
                            field.set(obj, injectObj);
                        }
                    }
                } else if ("byType".equals(autowireType)) {
                    //根据类型：
                    int count = 0;
                    for (Field field : fields) {
                        field.setAccessible(true);
                        Class<?> fieldClass = field.getType();
                        Object injectObj = null;
                        for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
                            injectObj = entry.getValue();
                            if (Objects.nonNull(injectObj) && injectObj.getClass().getInterfaces()[0].getName().equals(fieldClass.getName())) {
                                count++;
                            }
                        }

                        if (count > 1) {
                            throw new RuntimeException("byType自动装配，对象>1异常");
                        } else {
                            field.set(obj, injectObj);
                        }
                    }
                } else {
                    //其它:
                    System.out.println("自动装配其它类型");
                }


            }

            //3,如果obj为空,则生成放iocMap中
            if (obj == null) {
                obj = beanClass.newInstance();
            }
            iocMap.put(beanId, obj);


        }


    }

    public Object getBean(String beanName) {
        return iocMap.get(beanName);
    }
}
